using System.Collections.Generic;
using FireStarter.Base;
using FireStarter.CodeGeneration.Parser;
using FireStarterModeller.BO;

namespace FireStarter.CodeGeneration.Generator
{
    /// <summary>
    /// Provides a delegate to return a custom collection for a specified
    /// term encountered in a template
    /// </summary>
    /// <param name="modelElement">The model element that has the current scope
    /// when the term is encountered.  You can access parent classes or projects
    /// through the Parent property on the element.</param>
    /// <returns>Returns the collection to be interpreted by logic</returns>
    public delegate IEnumerable<IModelElement> CollectionDelegate(IModelElement modelElement);

    /// <summary>
    /// Manages a collection of delegates assigned to specific terms
    /// encountered in a code generation template.  Use these delegates when
    /// you need to assign custom behaviour and do not want to create or amend
    /// an interface or create a new action parser (which returns text and not values).
    /// </summary>
    /// <remarks>
    /// This class wraps a dictionary and stores all the delegate names in upper case.
    /// This is used to support case insensitivity, which was a stated option for the
    /// templates.
    /// </remarks>
    public class CollectionDelegatesDictionary
    {
        private readonly Dictionary<string, CollectionDelegate> _delegateDictionary = new Dictionary<string, CollectionDelegate>();

        public CollectionDelegatesDictionary()
        {
            AddDefaultCollectionDelegates();
        }

        private void AddDefaultCollectionDelegates()
        {
            Add("ModelClasses_OrderedForDeletion", OrderModelClassesForDeletionDelegate);
        }

        public void Add(string delegateName, CollectionDelegate theDelegate)
        {
            _delegateDictionary.Add(delegateName.ToUpper(), theDelegate);
        }

        public bool ContainsKey(string delegateName)
        {
            return _delegateDictionary.ContainsKey(delegateName.ToUpper());
        }

        public int Count
        {
            get { return _delegateDictionary.Count; }
        }

        public CollectionDelegate this[string delegateName]
        {
            get { return _delegateDictionary[delegateName.ToUpper()]; }
        }

        public IEnumerable<IModelElement> OrderModelClassesForDeletionDelegate(IModelElement modelElement)
        {
            Utilities.CheckDelegateContext("ModelClasses_OrderedForDeletion", modelElement, typeof (IModelSolution));
         
            IModelSolution modelSolution = (IModelSolution) modelElement;
            return Utilities.OrderModelClassesForDeletion(modelSolution.ModelClasses);
        }
    }
}